home *** CD-ROM | disk | FTP | other *** search
/ PsL Monthly 1993 December / PSL Monthly Shareware CD-ROM (December 1993).iso / prgmming / dos / c / intser.exe / INTSER.C < prev    next >
C/C++ Source or Header  |  1991-04-19  |  15KB  |  534 lines

  1. /************************************************************************/
  2. /*                                    */
  3. /*    Minimal Function, All C interrupt serial routine        */
  4. /*                                    */
  5. /*    Supports buffered input, output                    */
  6. /*                                    */
  7. /*                                    */
  8. /************************************************************************/
  9. /*                                    */
  10. /*    This code is donated to the public domain            */
  11. /*                                    */
  12. /************************************************************************/
  13.  
  14. #include <dos.h>
  15. #include <conio.h>
  16. #include <stdlib.h>
  17.  
  18. /************************************************************************/
  19. /*                                    */
  20. /*    The following callable subroutines are in this library        */
  21. /*                                    */
  22. /************************************************************************/
  23. int     ser_int_icount();    /* Count of chars in input buffer    */
  24. int     ser_int_ocount();    /* Count of chars in output buffer    */
  25. int     ser_int_ofree();    /* Count of free space in output buffer    */
  26. void    ser_int_iflush();    /* Flushes input buffer            */
  27. void    ser_int_init();        /* Initializes interrupt handler    */
  28. void    ser_int_term();        /* Terminates interrupt handler        */
  29. void    ser_int_putc();        /* Sends a character            */
  30. int     ser_int_getc();        /* Gets a character            */
  31. void    ser_int_puts();        /* Sends a string            */
  32. void    ser_int_break();    /* Sends a break signal            */
  33.  
  34. /************************************************************************/
  35. /*    Definitions of the 8250's registers                */
  36. /************************************************************************/
  37.  
  38. unsigned    ser_vect;    /* Interrupt vector to use        */
  39. unsigned    DataPort;    /* Data register            */
  40. unsigned    IER;        /* Interrupt enable register            */
  41. unsigned    IIR;        /* Interrupt  ID register        */
  42. unsigned    LCR;        /* Line control register        */
  43. unsigned    MControl;    /* Modem control register        */
  44. unsigned    LStatus;    /* Line Status                */
  45. unsigned    MStatus;    /* Modem status                */
  46.  
  47. unsigned    IntControl;    /* For 8259 interrupt controller        */
  48. unsigned    EnableIRQ4;    /* Enable interrupt 4            */
  49. unsigned    DisableIRQ4;    /* Disable interrupt 4            */
  50. unsigned    RS8259;
  51. unsigned    EOI;
  52. unsigned    TxReady;    /* Transmit buffer empty        */
  53.  
  54. static (_interrupt _far *old_vect)();
  55.                 /* The previous interrupt vector.    */
  56.  
  57. /************************************************************************/
  58. /*    Definitions of the interrupt enable register            */
  59. /************************************************************************/
  60.  
  61. #define    IER_RX        0x01    /* Enable Data Ready interrupts        */
  62. #define    IER_TX        0x02    /* Enable Transmit Empty Interrupts    */
  63. #define IER_LS          0x04    /* Enable line status interrupts        */
  64. #define IER_MS          0x08    /* Enable modem status interrupts       */
  65.  
  66. /************************************************************************/
  67. /*    Definitions of the interrupt ID register            */
  68. /************************************************************************/
  69. #define    IIR_IPending    0x01    /* Interrupt is pending            */
  70. #define    IIR_Mask    0x06    /* Mask to get Interrupt type        */
  71. #define    IIR_MS        0x00    /* Modem status interrupt        */
  72. #define    IIR_TX        0x02    /* Transmit empty interrupt        */
  73. #define    IIR_RX        0x04    /* Data available interrupt        */
  74. #define    IIR_LS        0x06    /* Line status interrupt        */
  75.  
  76. #define BUFSIZE         512     /* How many characters in the buffer?   */
  77. #define    XOFF_SIZE    384    /* How full do we get before XOFFing    */
  78. #define    XON_SIZE    128    /* How empty to we get before XONing    */
  79. #define    XOFF        19    /* value of the XOFF character        */
  80. #define    XON        17    /* value of the XON character        */
  81.  
  82. /************************************************************************/
  83. /*                                    */
  84. /*    Definitions for the input buffer.                */
  85. /*                                    */
  86. /*    We make it a 'far' array so as not to eat up valuable data    */
  87. /*    space in the small and medium models.                */
  88. /*                                    */
  89. /*    The buffers are simple circular buffers, where there is        */
  90. /*    one pointer to fill the buffer and another to empty it.        */
  91. /*    A count variable keeps track of the size of the buffer        */
  92. /*    (although it could be determined by computing             */
  93. /*    (fill-empty)%BUFSIZE).                        */
  94. /*                                    */
  95. /************************************************************************/
  96.  
  97. static unsigned char far in_buf[BUFSIZE];
  98. static int    in_fill        =0;    /* Where to place the next char    */
  99. static int    in_empty    =0;    /* Where to get the next char    */
  100. static int      in_count    =0;    /* How much data is in buffer    */
  101. static int    xoff_sent    =0;    /* Did we send an XOFF?        */
  102.  
  103. /************************************************************************/
  104. /*                                    */
  105. /*    Definitions for the output buffer                */
  106. /*                                    */
  107. /************************************************************************/
  108.  
  109. static unsigned char far out_buf[BUFSIZE];
  110. static int    out_fill    =0;
  111. static int    out_empty    =0;
  112. static int      out_count    =0;
  113.  
  114. static int    tx_off        =1;    /* These means the interrupts    */
  115.                     /* for the transmitter are now    */
  116.                     /* off (since we have nothing    */
  117.                     /* to send right now).        */
  118.  
  119. /************************************************************************/
  120. /*                                    */
  121. /*    ser_int_icount:        Return the number of bytes in the input    */
  122. /*                buffer.  0 means no data available.    */
  123. /*                                    */
  124. /************************************************************************/
  125. int     ser_int_icount()
  126. {
  127.     return(in_count);
  128. }
  129.  
  130. /************************************************************************/
  131. /*                                    */
  132. /*    ser_int_ocount:    Returns the number of bytes in the output    */
  133. /*            buffer. This information is useful if you    */
  134. /*            are uploading a large block of data and do    */
  135. /*            not want to hand this library data quicker    */
  136. /*            than it can be transmitted.  E.g.,        */
  137. /*                                    */
  138. /*                while (more data)            */
  139. /*                {                    */
  140. /*                    while (ser_int_ocount())    */
  141. /*                        ;            */
  142. /*                    send_data();            */
  143. /*                }                    */
  144. /*                                    */
  145. /************************************************************************/
  146. int     ser_int_ocount()
  147. {
  148.     return(out_count);
  149. }
  150.  
  151. /************************************************************************/
  152. /*                                    */
  153. /*    ser_int_ofree:    Returns the amount of free space left in    */
  154. /*            the output buffer.  Useful in preventing    */
  155. /*            hanging in ser_int_putc while sending a     */
  156. /*            a large block of data.  E.g.,            */
  157. /*                                    */
  158. /*                while (more_data)            */
  159. /*                {                    */
  160. /*                    while (ser_int_ofree() == 0)    */
  161. /*                        do_something_else();    */
  162. /*                    ser_int_putc(data);        */
  163. /*                }                    */
  164. /*                                    */
  165. /************************************************************************/
  166. int     ser_int_ofree()
  167. {
  168.     return(BUFSIZE-out_count);
  169. }
  170.  
  171. /************************************************************************/
  172. /*                                    */
  173. /*    ser_int_iflush:    Throw away any data in the input buffer.    */
  174. /*            Note that if a character arrives just as    */
  175. /*            this subroutine is returning, there will    */
  176. /*            be data in the input buffer upon return.    */
  177. /*            Thus, you cannot rely upon the buffer        */
  178. /*            being empty (for whatever reason).        */
  179. /*                                    */
  180. /************************************************************************/
  181. void    ser_int_iflush()
  182. {
  183.     _disable();
  184.  
  185.         /*****************************************/
  186.             in_fill        = 0;
  187.             in_empty    = 0;
  188.             in_count    = 0;
  189.         /*****************************************/
  190.  
  191.     _enable();
  192. }
  193.  
  194. /************************************************************************/
  195. /*                                    */
  196. /*    int_handler:        This routine catches the serial port    */
  197. /*                interrupts, and performs accordingly.    */
  198. /*                                    */
  199. /************************************************************************/
  200. static void interrupt far int_handler()
  201. {
  202.     int     ax;
  203.     static int send_now = 0;
  204.  
  205.     /* While there is more work to do...                */
  206.     while (0 == ((ax = inp(IIR)) & IIR_IPending))
  207.     {
  208.         switch (ax & IIR_Mask)
  209.         {
  210.         case IIR_RX:            /* New data has arrived    */
  211.  
  212.             ax      =inp(DataPort);
  213.  
  214.             if (in_count != BUFSIZE)
  215.             {
  216.                 in_buf[in_fill] = (unsigned char) ax;
  217.                 in_fill = (in_fill+1) & (BUFSIZE-1);
  218.                 in_count++;
  219.  
  220.                 /* Check for the buffer filling up...    */
  221.                 if ((in_count == XOFF_SIZE) && (!xoff_sent))
  222.                 {
  223.